import pandas as pd
import numpy as np
from scipy.stats import chi2_contingency
import plotly.express as px
import plotly.graph_objects as go
import plotly.subplots as sp
import scipy.stats as stats
import scikit_posthocs as sph
import seaborn as sns
import matplotlib as plt
df_merge = pd.read_csv("df_merge.csv")
df_age_categ = pd.read_csv("df_age_categ.csv")
df_nb_achat_categ = pd.read_csv("df_nb_achat_categ.csv")
df_age_categ.head()
| Unnamed: 0 | id_prod | price | categ | date | session_id | client_id | sex | birth | month | age | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0_1421 | 19.99 | 0 | 2021-03-01 04:13:00.107748 | s_101 | c_8533 | m | 1972 | 3 | 51 |
| 1 | 1 | 0_1421 | 19.99 | 0 | 2022-10-01 04:13:00.107748 | s_276043 | c_8533 | m | 1972 | 10 | 51 |
| 2 | 2 | 0_1421 | 19.99 | 0 | 2022-12-01 04:13:00.107748 | s_305391 | c_8533 | m | 1972 | 12 | 51 |
| 3 | 3 | 0_1421 | 19.99 | 0 | 2023-01-01 04:13:00.107748 | s_320253 | c_8533 | m | 1972 | 1 | 51 |
| 4 | 4 | 0_2199 | 12.99 | 0 | 2021-03-25 17:43:48.819074 | s_11366 | c_8533 | m | 1972 | 3 | 51 |
df_merge.head()
| Unnamed: 0 | client_id | age | sex | panier_total | nb_achat | premier_mois | dernier_mois | nb_mois | frequence_achat | item_par_panier | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | c_1 | 68 | m | 629.02 | 43 | 24258 | 24277 | 20 | 2.150000 | 1.264706 |
| 1 | 1 | c_10 | 67 | m | 1353.60 | 58 | 24255 | 24277 | 23 | 2.521739 | 1.705882 |
| 2 | 2 | c_100 | 31 | m | 254.85 | 8 | 24256 | 24273 | 18 | 0.444444 | 1.600000 |
| 3 | 3 | c_1000 | 57 | f | 2291.88 | 126 | 24255 | 24277 | 23 | 5.478261 | 1.340426 |
| 4 | 4 | c_1001 | 41 | m | 1823.85 | 103 | 24255 | 24278 | 24 | 4.291667 | 2.191489 |
df_merge = df_merge.drop(columns='Unnamed: 0')
bins = [18, 25, 40, 50, 65, 100]
labels = ["Jeunes adultes", "Jeunes actifs", "Familles & Pros", "Seniors actifs", "Retraités"]
df_merge["segment_age"] = pd.cut(df_merge["age"], bins=bins, labels=labels)
print(df_merge[["age", "segment_age"]].head())
age segment_age 0 68 Retraités 1 67 Retraités 2 31 Jeunes actifs 3 57 Seniors actifs 4 41 Familles & Pros
groupe_1 = df_merge[df_merge["segment_age"] == "Jeunes adultes"]
groupe_2 = df_merge[df_merge["segment_age"] == "Jeunes actifs"]
groupe_3 = df_merge[df_merge["segment_age"] == "Familles & Pros"]
groupe_4 = df_merge[df_merge["segment_age"] == "Seniors actifs"]
groupe_5 = df_merge[df_merge["segment_age"] == "Retraités"]
bins = [18, 25, 40, 50, 65, 100]
labels = ["Jeunes adultes", "Jeunes actifs", "Familles & Pros", "Seniors actifs", "Retraités"]
df_age_categ["segment_age"] = pd.cut(df_age_categ["age"], bins=bins, labels=labels)
print(df_age_categ[["age", "segment_age"]].head())
groupe_1_khi = df_age_categ[df_age_categ["segment_age"] == "Jeunes adultes"]
groupe_2_khi = df_age_categ[df_age_categ["segment_age"] == "Jeunes actifs"]
groupe_3_khi = df_age_categ[df_age_categ["segment_age"] == "Familles & Pros"]
groupe_4_khi = df_age_categ[df_age_categ["segment_age"] == "Seniors actifs"]
groupe_5_khi = df_age_categ[df_age_categ["segment_age"] == "Retraités"]
age segment_age 0 51 Seniors actifs 1 51 Seniors actifs 2 51 Seniors actifs 3 51 Seniors actifs 4 51 Seniors actifs
df_merge.head()
| client_id | age | sex | panier_total | nb_achat | premier_mois | dernier_mois | nb_mois | frequence_achat | item_par_panier | segment_age | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | c_1 | 68 | m | 629.02 | 43 | 24258 | 24277 | 20 | 2.150000 | 1.264706 | Retraités |
| 1 | c_10 | 67 | m | 1353.60 | 58 | 24255 | 24277 | 23 | 2.521739 | 1.705882 | Retraités |
| 2 | c_100 | 31 | m | 254.85 | 8 | 24256 | 24273 | 18 | 0.444444 | 1.600000 | Jeunes actifs |
| 3 | c_1000 | 57 | f | 2291.88 | 126 | 24255 | 24277 | 23 | 5.478261 | 1.340426 | Seniors actifs |
| 4 | c_1001 | 41 | m | 1823.85 | 103 | 24255 | 24278 | 24 | 4.291667 | 2.191489 | Familles & Pros |
df_age_categ.head()
| Unnamed: 0 | id_prod | price | categ | date | session_id | client_id | sex | birth | month | age | segment_age | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0_1421 | 19.99 | 0 | 2021-03-01 04:13:00.107748 | s_101 | c_8533 | m | 1972 | 3 | 51 | Seniors actifs |
| 1 | 1 | 0_1421 | 19.99 | 0 | 2022-10-01 04:13:00.107748 | s_276043 | c_8533 | m | 1972 | 10 | 51 | Seniors actifs |
| 2 | 2 | 0_1421 | 19.99 | 0 | 2022-12-01 04:13:00.107748 | s_305391 | c_8533 | m | 1972 | 12 | 51 | Seniors actifs |
| 3 | 3 | 0_1421 | 19.99 | 0 | 2023-01-01 04:13:00.107748 | s_320253 | c_8533 | m | 1972 | 1 | 51 | Seniors actifs |
| 4 | 4 | 0_2199 | 12.99 | 0 | 2021-03-25 17:43:48.819074 | s_11366 | c_8533 | m | 1972 | 3 | 51 | Seniors actifs |
def interpret_anderson(result):
for i in range(len(result.critical_values)):
sig_level = result.significance_level[i]
if result.statistic > result.critical_values[i]:
print(f"Au seuil de {sig_level}%, les données NE SUIVENT PAS une distribution normale.")
else:
print(f"Au seuil de {sig_level}%, les données SUIVENT une distribution normale.")
df_homme = df_merge[df_merge["sex"] == "m"]
df_femme = df_merge[df_merge["sex"] == "f"]
df_homme.head()
| client_id | age | sex | panier_total | nb_achat | premier_mois | dernier_mois | nb_mois | frequence_achat | item_par_panier | segment_age | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | c_1 | 68 | m | 629.02 | 43 | 24258 | 24277 | 20 | 2.150000 | 1.264706 | Retraités |
| 1 | c_10 | 67 | m | 1353.60 | 58 | 24255 | 24277 | 23 | 2.521739 | 1.705882 | Retraités |
| 2 | c_100 | 31 | m | 254.85 | 8 | 24256 | 24273 | 18 | 0.444444 | 1.600000 | Jeunes actifs |
| 4 | c_1001 | 41 | m | 1823.85 | 103 | 24255 | 24278 | 24 | 4.291667 | 2.191489 | Familles & Pros |
| 6 | c_1003 | 41 | m | 1230.83 | 106 | 24255 | 24278 | 24 | 4.416667 | 2.355556 | Familles & Pros |
df_counts = df_age_categ.groupby(["categ", "sex", "segment_age"]).size().unstack(fill_value=0).reset_index()
df_counts_2 = df_age_categ.groupby(["categ", "sex"]).size().unstack(fill_value=0).reset_index()
df_counts.head()
| segment_age | categ | sex | Jeunes adultes | Jeunes actifs | Familles & Pros | Seniors actifs | Retraités |
|---|---|---|---|---|---|---|---|
| 0 | 0 | f | 4990 | 71272 | 81206 | 28542 | 14783 |
| 1 | 0 | m | 4604 | 69736 | 72251 | 27567 | 12330 |
| 2 | 1 | f | 8743 | 28490 | 26199 | 32077 | 20212 |
| 3 | 1 | m | 8388 | 27018 | 23644 | 29849 | 15985 |
| 4 | 2 | f | 8647 | 7106 | 427 | 506 | 294 |
print(df_counts.columns)
Index(['categ', 'sex', 'Jeunes adultes', 'Jeunes actifs', 'Familles & Pros',
'Seniors actifs', 'Retraités'],
dtype='object', name='segment_age')
df_counts = df_counts.set_index(["categ", "sex"])
cols_effectifs = ["Jeunes adultes", "Jeunes actifs", "Familles & Pros", "Seniors actifs", "Retraités"]
table_contingence = df_counts[cols_effectifs]
chi2, p_value, dof, expected = chi2_contingency(table_contingence)
print("Chi² =", chi2)
print("p-value =", p_value)
print("Degrés de liberté =", dof)
n = table_contingence.to_numpy().sum()
min_dim = min(table_contingence.shape)
v_cramer = np.sqrt((chi2 / n) / min_dim)
print("V de Cramer =", v_cramer)
Chi² = 170895.3041612725 p-value = 0.0 Degrés de liberté = 20 V de Cramer = 0.23096234347711397
print(df_counts.columns)
Index(['Jeunes adultes', 'Jeunes actifs', 'Familles & Pros', 'Seniors actifs',
'Retraités'],
dtype='object', name='segment_age')
colonnes_a_comparer = ["f", "m"]
df_subset = df_counts_2[colonnes_a_comparer]
df_long = df_counts_2.melt(id_vars="categ", var_name="Sexe", value_name="Effectif")
tableau_contingence = pd.crosstab(df_long["categ"], df_long["Sexe"], values=df_long["Effectif"], aggfunc="sum")
df_subset.head()
| sex | f | m |
|---|---|---|
| 0 | 200793 | 186488 |
| 1 | 115721 | 104884 |
| 2 | 16980 | 15868 |
stat, p, dof, expected = stats.chi2_contingency(tableau_contingence)
N = tableau_contingence.sum().sum()
cramer_v = np.sqrt(stat / (N * min(2, 2)))
print(f"Statistique Khi-2 : {stat}")
print(f"P-valeur : {p:.2f}")
print(f"V de Cramer : {cramer_v:.4f}")
print(f"Degrés de liberté : {dof}")
df_khi = pd.DataFrame(expected)
alpha = 0.05
if p < alpha:
print("Il y a une dépendance significative entre les catégories et le sexe (Rejet de H0).")
else:
print("Aucune dépendance significative (On ne rejette pas H0).")
Statistique Khi-2 : 22.66856665178056 P-valeur : 0.00 V de Cramer : 0.0042 Degrés de liberté : 2 Il y a une dépendance significative entre les catégories et le sexe (Rejet de H0).
df_khi.index.name = "categ"
df_khi = df_khi.astype(int)
df_merge_khi = pd.merge(df_counts, df_khi, how="inner", on='categ')
df_merge_khi.head()
| Jeunes adultes | Jeunes actifs | Familles & Pros | Seniors actifs | Retraités | 0 | 1 | |
|---|---|---|---|---|---|---|---|
| categ | |||||||
| 0 | 4990 | 71272 | 81206 | 28542 | 14783 | 201574 | 185706 |
| 0 | 4604 | 69736 | 72251 | 27567 | 12330 | 201574 | 185706 |
| 1 | 8743 | 28490 | 26199 | 32077 | 20212 | 114822 | 105782 |
| 1 | 8388 | 27018 | 23644 | 29849 | 15985 | 114822 | 105782 |
| 2 | 8647 | 7106 | 427 | 506 | 294 | 17096 | 15751 |
df_merge_khi = df_merge_khi.rename(columns={"f":"fo", "m":"mo", 0:"fe", 1:"me"})
df_merge_khi.head()
| Jeunes adultes | Jeunes actifs | Familles & Pros | Seniors actifs | Retraités | fe | me | |
|---|---|---|---|---|---|---|---|
| categ | |||||||
| 0 | 4990 | 71272 | 81206 | 28542 | 14783 | 201574 | 185706 |
| 0 | 4604 | 69736 | 72251 | 27567 | 12330 | 201574 | 185706 |
| 1 | 8743 | 28490 | 26199 | 32077 | 20212 | 114822 | 105782 |
| 1 | 8388 | 27018 | 23644 | 29849 | 15985 | 114822 | 105782 |
| 2 | 8647 | 7106 | 427 | 506 | 294 | 17096 | 15751 |
df_merge.head()
| client_id | age | sex | panier_total | nb_achat | premier_mois | dernier_mois | nb_mois | frequence_achat | item_par_panier | segment_age | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | c_1 | 68 | m | 629.02 | 43 | 24258 | 24277 | 20 | 2.150000 | 1.264706 | Retraités |
| 1 | c_10 | 67 | m | 1353.60 | 58 | 24255 | 24277 | 23 | 2.521739 | 1.705882 | Retraités |
| 2 | c_100 | 31 | m | 254.85 | 8 | 24256 | 24273 | 18 | 0.444444 | 1.600000 | Jeunes actifs |
| 3 | c_1000 | 57 | f | 2291.88 | 126 | 24255 | 24277 | 23 | 5.478261 | 1.340426 | Seniors actifs |
| 4 | c_1001 | 41 | m | 1823.85 | 103 | 24255 | 24278 | 24 | 4.291667 | 2.191489 | Familles & Pros |
bins = [18, 25, 40, 50, 65, 100]
labels = ["Jeunes adultes", "Jeunes actifs", "Familles & Pros", "Seniors actifs", "Retraités"]
df_merge["segment_age"] = pd.cut(df_merge["age"], bins=bins, labels=labels)
print(df_merge[["age", "segment_age"]].head())
age segment_age 0 68 Retraités 1 67 Retraités 2 31 Jeunes actifs 3 57 Seniors actifs 4 41 Familles & Pros
df_merge.head()
| client_id | age | sex | panier_total | nb_achat | premier_mois | dernier_mois | nb_mois | frequence_achat | item_par_panier | segment_age | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | c_1 | 68 | m | 629.02 | 43 | 24258 | 24277 | 20 | 2.150000 | 1.264706 | Retraités |
| 1 | c_10 | 67 | m | 1353.60 | 58 | 24255 | 24277 | 23 | 2.521739 | 1.705882 | Retraités |
| 2 | c_100 | 31 | m | 254.85 | 8 | 24256 | 24273 | 18 | 0.444444 | 1.600000 | Jeunes actifs |
| 3 | c_1000 | 57 | f | 2291.88 | 126 | 24255 | 24277 | 23 | 5.478261 | 1.340426 | Seniors actifs |
| 4 | c_1001 | 41 | m | 1823.85 | 103 | 24255 | 24278 | 24 | 4.291667 | 2.191489 | Familles & Pros |
groupe_1 = df_merge[df_merge["segment_age"] == "Jeunes adultes"]["panier_total"]
groupe_2 = df_merge[df_merge["segment_age"] == "Jeunes actifs"]["panier_total"]
groupe_3 = df_merge[df_merge["segment_age"] == "Familles & Pros"]["panier_total"]
groupe_4 = df_merge[df_merge["segment_age"] == "Seniors actifs"]["panier_total"]
groupe_5 = df_merge[df_merge["segment_age"] == "Retraités"]["panier_total"]
l_stat, p_value = stats.levene(groupe_1, groupe_2, groupe_3, groupe_4, groupe_5)
print(f"Test de levene: {l_stat:.3f}")
print(f"Valeur p: {p_value:.5f}")
Test de levene: 92.458 Valeur p: 0.00000
fig = px.scatter(df_merge, x="age", y="panier_total",
title="Relation entre l'âge et le montant dépensé au total",
labels={"age": "Âge du client", "montant_panier": "Montant du panier (€)"},
trendline="lowess")
fig.show()
groupes = {
"Jeunes adultes": groupe_1,
"Jeunes actifs": groupe_2,
"Familles & Pros": groupe_3,
"Seniors actifs": groupe_4,
"Retraités": groupe_5
}
for nom, groupe in groupes.items():
result = stats.anderson(groupe, dist='norm')
print(f"\nTest d'Anderson-Darling pour {nom}")
interpret_anderson(result)
Test d'Anderson-Darling pour Jeunes adultes Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Jeunes actifs Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Familles & Pros Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Seniors actifs Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Retraités Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale.
anderson_age = stats.anderson(df_merge["age"], dist='norm')
print("Test d'Anderson-Darling pour Age")
print(f"Statistique : {anderson_age.statistic:.4f}")
print(f"Valeurs critiques : {anderson_age.critical_values}")
print(f"Niveaux de signification : {anderson_age.significance_level}")
print("\nInterprétation pour Age :")
interpret_anderson(anderson_age)
Test d'Anderson-Darling pour Age Statistique : 53.7635 Valeurs critiques : [0.576 0.656 0.787 0.918 1.091] Niveaux de signification : [15. 10. 5. 2.5 1. ] Interprétation pour Age : Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale.
stat, p_value = stats.kruskal(groupe_1, groupe_2, groupe_3, groupe_4, groupe_5)
print(f" Kruskal-Wallis : Statistique H = {stat:.4f}")
print(f" p-value = {p_value:.5f}")
if p_value < 0.05:
print("Il y a une différence significative entre au moins un des groupes.")
else:
print("Pas de différence significative entre les groupes.")
Kruskal-Wallis : Statistique H = 537.4040 p-value = 0.00000 Il y a une différence significative entre au moins un des groupes.
data = [groupe_1, groupe_2, groupe_3, groupe_4, groupe_5]
dunn_results = sph.posthoc_dunn(data, p_adjust="bonferroni")
dunn_df = pd.DataFrame(dunn_results.values, index=labels, columns=labels)
fig = px.imshow(
dunn_df,
labels=dict(x="Groupe 1", y="Groupe 2", color="p-value"),
x=labels,
y=labels,
color_continuous_scale="RdBu_r",
title="Test post-hoc de Dunn (p-values)"
)
fig.show()
df_test = df_merge.groupby(["segment_age"])
for i, o in df_test:
correlation, p_value = stats.spearmanr(o['age'], o['panier_total'])
print(f"{i}, {correlation:.5f}")
print(f"{i}, {p_value:.5f}")
print()
('Jeunes adultes',), -0.00839
('Jeunes adultes',), 0.76402
('Jeunes actifs',), 0.11571
('Jeunes actifs',), 0.00000
('Familles & Pros',), 0.01071
('Familles & Pros',), 0.65309
('Seniors actifs',), -0.07534
('Seniors actifs',), 0.00089
('Retraités',), -0.03969
('Retraités',), 0.17583
"""
Les variables ne suivent pas une variance équivalente entre elles
La distribution n'est pas normale
Le panier moyen décroit avec l'age qui avance
La relation entre les deux variable est très significative mais pas énorme
"""
"\nLes variables ne suivent pas une variance équivalente entre elles \nLa distribution n'est pas normale\nLe panier moyen décroit avec l'age qui avance\nLa relation entre les deux variable est très significative mais pas énorme\n\n"
df_merge.head()
| client_id | age | sex | panier_total | nb_achat | premier_mois | dernier_mois | nb_mois | frequence_achat | item_par_panier | segment_age | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | c_1 | 68 | m | 629.02 | 43 | 24258 | 24277 | 20 | 2.150000 | 1.264706 | Retraités |
| 1 | c_10 | 67 | m | 1353.60 | 58 | 24255 | 24277 | 23 | 2.521739 | 1.705882 | Retraités |
| 2 | c_100 | 31 | m | 254.85 | 8 | 24256 | 24273 | 18 | 0.444444 | 1.600000 | Jeunes actifs |
| 3 | c_1000 | 57 | f | 2291.88 | 126 | 24255 | 24277 | 23 | 5.478261 | 1.340426 | Seniors actifs |
| 4 | c_1001 | 41 | m | 1823.85 | 103 | 24255 | 24278 | 24 | 4.291667 | 2.191489 | Familles & Pros |
bins = [18, 25, 40, 50, 65, 100]
labels = ["Jeunes adultes", "Jeunes actifs", "Familles & Pros", "Seniors actifs", "Retraités"]
df_merge["segment_age"] = pd.cut(df_merge["age"], bins=bins, labels=labels)
print(df_merge[["age", "segment_age"]].head())
age segment_age 0 68 Retraités 1 67 Retraités 2 31 Jeunes actifs 3 57 Seniors actifs 4 41 Familles & Pros
groupe_1 = df_merge[df_merge["segment_age"] == "Jeunes adultes"]["frequence_achat"]
groupe_2 = df_merge[df_merge["segment_age"] == "Jeunes actifs"]["frequence_achat"]
groupe_3 = df_merge[df_merge["segment_age"] == "Familles & Pros"]["frequence_achat"]
groupe_4 = df_merge[df_merge["segment_age"] == "Seniors actifs"]["frequence_achat"]
groupe_5 = df_merge[df_merge["segment_age"] == "Retraités"]["frequence_achat"]
groupes = {
"Jeunes adultes": groupe_1,
"Jeunes actifs": groupe_2,
"Familles & Pros": groupe_3,
"Seniors actifs": groupe_4,
"Retraités": groupe_5
}
for nom, groupe in groupes.items():
result = stats.anderson(groupe, dist='norm')
print(f"\nTest d'Anderson-Darling pour {nom}")
interpret_anderson(result)
Test d'Anderson-Darling pour Jeunes adultes Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Jeunes actifs Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Familles & Pros Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Seniors actifs Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Retraités Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale.
anderson_panier = stats.anderson(df_merge["frequence_achat"], dist='norm')
print("\nTest d'Anderson-Darling pour Panier Total")
print(f"Statistique : {anderson_panier.statistic:.4f}")
print(f"Valeurs critiques : {anderson_panier.critical_values}")
print(f"Niveaux de signification : {anderson_panier.significance_level}")
def interpret_anderson(result):
for i in range(len(result.critical_values)):
sig_level = result.significance_level[i]
if result.statistic > result.critical_values[i]:
print(f"Au seuil de {sig_level}%, les données NE SUIVENT PAS une distribution normale.")
else:
print(f"Au seuil de {sig_level}%, les données SUIVENT une distribution normale.")
print("\nInterprétation pour Age :")
interpret_anderson(anderson_age)
print("\nInterprétation pour Panier Total :")
interpret_anderson(anderson_panier)
Test d'Anderson-Darling pour Panier Total Statistique : 479.4178 Valeurs critiques : [0.576 0.656 0.787 0.918 1.091] Niveaux de signification : [15. 10. 5. 2.5 1. ] Interprétation pour Age : Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Interprétation pour Panier Total : Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale.
k_stats, p_value = stats.kruskal(groupe_1, groupe_2, groupe_3, groupe_4, groupe_5)
print(f"{k_stats:.5f}")
print(f"{p_value:.5f}")
1388.89986 0.00000
data = [groupe_1, groupe_2, groupe_3, groupe_4, groupe_5]
dunn_results = sph.posthoc_dunn(data, p_adjust="bonferroni")
dunn_df = pd.DataFrame(dunn_results.values, index=labels, columns=labels)
fig = px.imshow(
dunn_df,
labels=dict(x="Groupe 1", y="Groupe 2", color="p-value"),
x=labels,
y=labels,
color_continuous_scale="RdBu_r",
title="Test post-hoc de Dunn (p-values)"
)
fig.show()
fig = px.scatter(df_merge, x="age", y="frequence_achat",
title="Relation entre l'âge et la fréquence d'achat",
labels={"age": "Âge du client", "frequence_achat": "Nombre d'achat par mois"},
trendline="lowess")
fig.show()
df_test = df_merge.groupby(["segment_age"])
for i, o in df_test:
correlation, p_value = stats.spearmanr(o['age'], o['frequence_achat'])
print(f"{i}, {correlation:.5f}")
print(f"{i}, {p_value:.5f}")
print()
('Jeunes adultes',), -0.01266
('Jeunes adultes',), 0.65058
('Jeunes actifs',), 0.55830
('Jeunes actifs',), 0.00000
('Familles & Pros',), 0.01666
('Familles & Pros',), 0.48415
('Seniors actifs',), -0.10346
('Seniors actifs',), 0.00000
('Retraités',), -0.03891
('Retraités',), 0.18449
"""
Il y a des différences significative entre les groupes d'âges
La fréquence d'achat corrèle positivement avec l'âge
On peut en déduire que chaque générations a ses habitudes ?
"""
"\nIl y a des différences significative entre les groupes d'âges\nLa fréquence d'achat corrèle positivement avec l'âge\nOn peut en déduire que chaque générations a ses habitudes ?\n"
print(df_merge["frequence_achat"].describe())
count 8596.000000 mean 3.206055 std 2.796067 min 0.111111 25% 1.304348 50% 2.291667 75% 4.125000 max 16.875000 Name: frequence_achat, dtype: float64
hommes = df_merge[df_merge["sex"] == "m"]["frequence_achat"]
femmes = df_merge[df_merge["sex"] == "f"]["frequence_achat"]
df_merge.head()
| client_id | age | sex | panier_total | nb_achat | premier_mois | dernier_mois | nb_mois | frequence_achat | item_par_panier | segment_age | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | c_1 | 68 | m | 629.02 | 43 | 24258 | 24277 | 20 | 2.150000 | 1.264706 | Retraités |
| 1 | c_10 | 67 | m | 1353.60 | 58 | 24255 | 24277 | 23 | 2.521739 | 1.705882 | Retraités |
| 2 | c_100 | 31 | m | 254.85 | 8 | 24256 | 24273 | 18 | 0.444444 | 1.600000 | Jeunes actifs |
| 3 | c_1000 | 57 | f | 2291.88 | 126 | 24255 | 24277 | 23 | 5.478261 | 1.340426 | Seniors actifs |
| 4 | c_1001 | 41 | m | 1823.85 | 103 | 24255 | 24278 | 24 | 4.291667 | 2.191489 | Familles & Pros |
groupe_1 = df_merge[df_merge["segment_age"] == "Jeunes adultes"]["item_par_panier"]
groupe_2 = df_merge[df_merge["segment_age"] == "Jeunes actifs"]["item_par_panier"]
groupe_3 = df_merge[df_merge["segment_age"] == "Familles & Pros"]["item_par_panier"]
groupe_4 = df_merge[df_merge["segment_age"] == "Seniors actifs"]["item_par_panier"]
groupe_5 = df_merge[df_merge["segment_age"] == "Retraités"]["item_par_panier"]
groupes = {
"Jeunes adultes": groupe_1,
"Jeunes actifs": groupe_2,
"Familles & Pros": groupe_3,
"Seniors actifs": groupe_4,
"Retraités": groupe_5
}
for nom, groupe in groupes.items():
result = stats.anderson(groupe, dist='norm')
print(f"\nTest d'Anderson-Darling pour {nom}")
interpret_anderson(result)
Test d'Anderson-Darling pour Jeunes adultes Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Jeunes actifs Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Familles & Pros Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Seniors actifs Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Test d'Anderson-Darling pour Retraités Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale.
fig = px.scatter(df_merge, x="age", y="item_par_panier",
title="Relation entre l'âge et le nombre de produit par panier",
labels={"age": "Âge du client", "item_par_panier": "Nombre de produit par panier"},
trendline="lowess")
fig.show()
spearman_corr, p_value = stats.spearmanr(df_merge["age"], df_merge["item_par_panier"])
print(f"Corrélation de Spearman: {spearman_corr:.3f}")
print(f"Valeur p: {p_value:.5f}")
Corrélation de Spearman: -0.208 Valeur p: 0.00000
df_test = df_merge.groupby(["segment_age"])
for i, o in df_test:
correlation, p_value = stats.spearmanr(o['age'], o['item_par_panier'])
print(f"{i}, {correlation:.5f}")
print(f"{i}, {p_value:.5f}")
print()
('Jeunes adultes',), 0.00842
('Jeunes adultes',), 0.76320
('Jeunes actifs',), 0.45837
('Jeunes actifs',), 0.00000
('Familles & Pros',), 0.02529
('Familles & Pros',), 0.28833
('Seniors actifs',), -0.15349
('Seniors actifs',), 0.00000
('Retraités',), 0.01323
('Retraités',), 0.65200
anderson_item_par_panier = stats.anderson(df_merge["item_par_panier"], dist='norm')
print(f"Statistique : {anderson_item_par_panier.statistic:.4f}")
print(f"Valeurs critiques : {anderson_item_par_panier.critical_values}")
print(f"Niveaux de signification : {anderson_item_par_panier.significance_level}")
print("\nInterprétation pour Age :")
interpret_anderson(anderson_age)
print("\nInterprétation pour Age :")
interpret_anderson(anderson_item_par_panier)
Statistique : 77.9237 Valeurs critiques : [0.576 0.656 0.787 0.918 1.091] Niveaux de signification : [15. 10. 5. 2.5 1. ] Interprétation pour Age : Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale. Interprétation pour Age : Au seuil de 15.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 10.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 5.0%, les données NE SUIVENT PAS une distribution normale. Au seuil de 2.5%, les données NE SUIVENT PAS une distribution normale. Au seuil de 1.0%, les données NE SUIVENT PAS une distribution normale.
m_stat, p_value = stats.kruskal(groupe_1, groupe_2, groupe_3, groupe_4, groupe_5)
print(f"{m_stat:.5f}")
print(f"{p_value:.5f}")
2777.34075 0.00000
data = [groupe_1, groupe_2, groupe_3, groupe_4, groupe_5]
dunn_results = sph.posthoc_dunn(data, p_adjust="bonferroni")
dunn_df = pd.DataFrame(dunn_results.values, index=labels, columns=labels)
fig = px.imshow(
dunn_df,
labels=dict(x="Groupe 1", y="Groupe 2", color="p-value"),
x=labels,
y=labels,
color_continuous_scale="RdBu_r",
title="Test post-hoc de Dunn (p-values)"
)
fig.show()
df_nb_achat_categ = df_nb_achat_categ.drop(columns="Unnamed: 0")
df_nb_achat_categ.head()
| client_id | categ | age | depense_par_categ | nb_achat | |
|---|---|---|---|---|---|
| 0 | c_1 | 0 | 70 | 360.15 | 30.0 |
| 1 | c_1 | 1 | 70 | 214.00 | 12.0 |
| 2 | c_1 | 2 | 70 | 54.87 | 1.0 |
| 3 | c_10 | 0 | 69 | 263.87 | 20.0 |
| 4 | c_10 | 1 | 69 | 809.77 | 34.0 |
df_nb_achat_categ["Jitter"] = df_nb_achat_categ["categ"].astype(float) + np.random.uniform(-0.4, 0.4, len(df_nb_achat_categ))
fig = px.scatter(
df_nb_achat_categ,
x="Jitter",
y="age",
size="nb_achat",
color=df_nb_achat_categ["categ"].astype(str),
labels={"Jitter": "Catégorie d'achat", "age": "Âge", "nb_achat": "Nombre d'achats"},
title="Répartition des âges par catégorie d'achat (Taille = Nombre d'achats)",
opacity=0.7
)
fig.update_layout(
xaxis=dict(tickmode="array", tickvals=[0, 1, 2], ticktext=["Catégorie 0", "Catégorie 1", "Catégorie 2"]),
xaxis_title="Catégorie d'achat",
yaxis_title="Âge",
height = 650
)
fig.show()
df_nb_achat_categ.head()
| client_id | categ | age | depense_par_categ | nb_achat | Jitter | |
|---|---|---|---|---|---|---|
| 0 | c_1 | 0 | 70 | 360.15 | 30.0 | 0.292943 |
| 1 | c_1 | 1 | 70 | 214.00 | 12.0 | 0.964251 |
| 2 | c_1 | 2 | 70 | 54.87 | 1.0 | 2.291610 |
| 3 | c_10 | 0 | 69 | 263.87 | 20.0 | 0.356798 |
| 4 | c_10 | 1 | 69 | 809.77 | 34.0 | 1.100067 |
df_nb_achat_categ["segment_age"] = pd.cut(df_nb_achat_categ["age"], bins=bins, labels=labels)
d_age = {}
d_categ = {}
nb_segment = df_nb_achat_categ['segment_age'].unique()
nb_categ = df_nb_achat_categ['categ'].unique()
for i in range(len(nb_segment)):
d_age[f"groupe_{i}"] = df_nb_achat_categ.loc[df_nb_achat_categ['segment_age'] == nb_segment[i], ['categ', 'depense_par_categ', 'segment_age', 'age']]
for key in d_age:
for o in range(len(nb_categ)):
d_categ[f"{key}_{o}"] = d_age[key].loc[d_age[key]['categ'] == nb_categ[o], ['categ','depense_par_categ', 'segment_age', 'age']]
print(d_categ.keys())
dict_keys(['groupe_0_0', 'groupe_0_1', 'groupe_0_2', 'groupe_1_0', 'groupe_1_1', 'groupe_1_2', 'groupe_2_0', 'groupe_2_1', 'groupe_2_2', 'groupe_3_0', 'groupe_3_1', 'groupe_3_2', 'groupe_4_0', 'groupe_4_1', 'groupe_4_2'])
data = []
for i in d_categ.keys():
data.append(i)
print(data)
['groupe_0_0', 'groupe_0_1', 'groupe_0_2', 'groupe_1_0', 'groupe_1_1', 'groupe_1_2', 'groupe_2_0', 'groupe_2_1', 'groupe_2_2', 'groupe_3_0', 'groupe_3_1', 'groupe_3_2', 'groupe_4_0', 'groupe_4_1', 'groupe_4_2']
d_categ['groupe_0_0'].head()
| categ | depense_par_categ | segment_age | age | |
|---|---|---|---|---|
| 0 | 0 | 360.15 | Retraités | 70 |
| 3 | 0 | 263.87 | Retraités | 69 |
| 24 | 0 | 250.36 | Retraités | 84 |
| 30 | 0 | 138.08 | Retraités | 84 |
| 48 | 0 | 103.57 | Retraités | 68 |
for nom, df in d_categ.items():
valeurs = pd.to_numeric(df['depense_par_categ'], errors='coerce').dropna()
result = stats.anderson(valeurs, dist='norm')
if result.statistic > 1.089:
continue
print(f"Test d'Anderson-Darling pour {nom}")
interpret_anderson(result)
data = [
pd.to_numeric(df["depense_par_categ"], errors="coerce").dropna().values
for df in d_categ.values()
]
k_stat, p_value = stats.kruskal(*data)
print(f"{k_stat:.5f}")
print(f"{p_value:.5f}")
11406.79242 0.00000
correlation, p_value = stats.spearmanr(df_nb_achat_categ['age'], df_nb_achat_categ['depense_par_categ'])
print(f"{correlation:.5f}")
print(f"{p_value:.5f}")
-0.08537 0.00000
df_test = df_nb_achat_categ.groupby(["segment_age", "categ"])
for i, o in df_test:
correlation, p_value = stats.spearmanr(o['age'], o['depense_par_categ'])
print(f"{i}, {correlation:.5f}")
print(f"{i}, {p_value:.5f}")
print()
('Jeunes adultes', 0), 0.01481
('Jeunes adultes', 0), 0.64201
('Jeunes adultes', 1), -0.06838
('Jeunes adultes', 1), 0.03162
('Jeunes adultes', 2), -0.03520
('Jeunes adultes', 2), 0.26897
('Jeunes actifs', 0), 0.70721
('Jeunes actifs', 0), 0.00000
('Jeunes actifs', 1), 0.36970
('Jeunes actifs', 1), 0.00000
('Jeunes actifs', 2), -0.71550
('Jeunes actifs', 2), 0.00000
('Familles & Pros', 0), -0.03779
('Familles & Pros', 0), 0.11185
('Familles & Pros', 1), -0.03260
('Familles & Pros', 1), 0.17030
('Familles & Pros', 2), -0.04720
('Familles & Pros', 2), 0.04702
('Seniors actifs', 0), -0.36578
('Seniors actifs', 0), 0.00000
('Seniors actifs', 1), 0.03303
('Seniors actifs', 1), 0.13539
('Seniors actifs', 2), 0.00544
('Seniors actifs', 2), 0.80583
('Retraités', 0), -0.02935
('Retraités', 0), 0.27733
('Retraités', 1), -0.02213
('Retraités', 1), 0.41275
('Retraités', 2), -0.00948
('Retraités', 2), 0.72577